using System.Diagnostics;
using System.Text;
using Aurora.Security.RSA.Util;

namespace Gateway.UI.Api.Extensions.Middlewares;

/// <summary>
/// context 中间件
/// </summary>
public class HttpContextMiddleware : IMiddleware
{
    private readonly ILogger _logger;
    private readonly IRSAUtil _rsa;

    /// <summary>
    /// 计时器
    /// </summary>
    private Stopwatch _stopwatch;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="loggerFactory"></param>
    /// <param name="rsa"></param>
    public HttpContextMiddleware(ILoggerFactory loggerFactory, IRSAUtil rsa)
    {
        _rsa = rsa;
        _logger = loggerFactory.CreateLogger<HttpContextMiddleware>();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    /// <param name="next"></param>
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        context.Request.EnableBuffering();
        _stopwatch = new Stopwatch();
        _stopwatch.Start();
        _logger.LogInformation($"Handling request: " + context.Request.Path);
        var request = context.Request.Body;
        var response = context.Response.Body;
        var body = string.Empty;
        var responseBody = string.Empty;
        try
        {
            using (var newRequest = new MemoryStream())
            {
                context.Request.Body = newRequest;

                using (var newResponse = new MemoryStream())
                {
                    context.Response.Body = newResponse;
                    using (var reader = new StreamReader(request))
                    {
                        //读取原始请求流内容
                        body = await reader.ReadToEndAsync();
                        if (string.IsNullOrEmpty(body))
                        {
                            await next.Invoke(context);
                        }
                        else
                        {
                            //todo 解密
                            using (var writer = new StreamWriter(newRequest))
                            {
                                await writer.WriteAsync(body);
                                await writer.FlushAsync();
                                newRequest.Position = 0;
                                context.Request.Body = newRequest;
                                await next(context);
                            }
                        }
                    }

                    using (var reader = new StreamReader(newResponse))
                    {
                        newResponse.Position = 0;
                        responseBody = await reader.ReadToEndAsync();
                        if (!string.IsNullOrEmpty(responseBody))
                        {
                            //todo 加密
                            responseBody = await _rsa.EncryptAsync(responseBody);
                        }
                    }
                    // SecurityAESCore.ToAes128EncryptString()
                    var byteArray = Encoding.UTF8.GetBytes(responseBody);
                    // 更新 Content-Length 字段
                    context.Response.ContentLength =byteArray.Length;

                    using (var writer = new StreamWriter(response))
                    {
                        //response.Position = 0;
                        await writer.WriteAsync(responseBody);
                        await writer.FlushAsync();
                    }
                }
            }
        }
        catch (Exception e)
        {
            _logger.LogError($" http中间件发生错误: " + e.ToString());
        }
        finally
        {
            context.Request.Body = request;
            context.Response.Body = response;
        }

        // 响应完成时存入缓存
        context.Response.OnCompleted(() =>
        {
            _stopwatch.Stop();
            var elapsedTime = _stopwatch.ElapsedMilliseconds;

            _logger.LogWarning(
                $"RequestLog:{DateTime.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(0, 10000)}-{elapsedTime}ms");
            return Task.CompletedTask;
        });

        _logger.LogInformation($"Finished handling request.{_stopwatch.ElapsedMilliseconds}ms");
    }
}